/*
 * SnmpApi.cpp
 *
 *  Created on: 2014-10-11
 *      Author: root
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include"Common.h"
#include"PublicLog.h"
#include"PublicThread.h"
#include"PublicTool.h"
#include"SnmpApi.h"
//用于连接加锁
PublicLock m_snmplock;
MAPSTRINGLIST m_PublicList;//存储团体信息
void UpdateSnmpCommunity(const char*IP,const char*community){
	if(community==NULL||community[0]=='\0')
		return;
	m_snmplock.Lock();
	MAPSTRINGLIST::iterator it=m_PublicList.find(IP);
	if(it!=m_PublicList.end()){
		it->second=community;
	}else{
		m_PublicList.insert(std::pair<std::string,std::string>(IP,community));
	}
	m_snmplock.UnLock();
}
void GetSnmpCommunity(const char*IP,char*community,int size){
	m_snmplock.Lock();
	MAPSTRINGLIST::iterator it=m_PublicList.find(IP);
	if(it!=m_PublicList.end()){
		strncpy(community,it->second.c_str(),size);
	}else{
		strncpy(community,g_sysconf.community,size);
	}
	m_snmplock.UnLock();
}
MAPSTRINGLIST  GetSnmpCommunity(){
	MAPSTRINGLIST tmp;
	m_snmplock.Lock();
	tmp=m_PublicList;
	m_snmplock.UnLock();
	return tmp;
}
void ShowErrInfo(void*ss,netsnmp_pdu*pdu,int status);
int GetSnmpResponse(void*ss,netsnmp_pdu*pdu, netsnmp_pdu **response){
	if(pdu==NULL){
		WRONG("IP:%s PDU is NULL",GetSnmpPeerName(ss));
		return STAT_TIMEOUT;
	}
	if(pdu->variables==NULL){
		WRONG("IP:%s PDU With NULL Variables",GetSnmpPeerName(ss));
		snmp_free_pdu(pdu);
		return STAT_TIMEOUT;
	}
	netsnmp_pdu*pdutemp=snmp_clone_pdu(pdu);
	int status=snmp_sess_synch_response(ss,pdutemp,response);
	if(*response && (*response)->errstat != SNMP_ERR_NOERROR){
		WRONG("IP:%s 获取包错误:%s",GetSnmpPeerName(ss),snmp_errstring((*response)->errstat));
	}
	if(status!=STAT_SUCCESS){
		ShowErrInfo(ss,pdu,status);
	}
	snmp_free_pdu(pdu);
	return status;
}
//根据宏定义选择
#if HAVE_SYS_CONFIG
#define SNMP_API_DEFAULT_TIMEOUT g_sysconf.snmptimeout*1000
#defien SNMP_API_DEFAULT_RETRIES g_sysconf.snmpretrys
#else
#define SNMP_API_DEFAULT_TIMEOUT 5000000
#define SNMP_API_DEFAULT_RETRIES 3
#endif
void*OpenSnmp(const char*IP){
	netsnmp_session session;
	void*ss=NULL;
	snmp_sess_init(&session);
	session.peername=(char*)IP;
	session.version=SNMP_VERSION_2c;
#if 0	
	session.community=(u_char*)g_sysconf.community;
	session.community_len=strlen(g_sysconf.community);
#else
	char community[128]={0};
	GetSnmpCommunity(IP,community,127);
	session.community=(u_char*)community;
	session.community_len=strlen(community);
#endif	
// session.timeout=1000000;
	session.timeout=SNMP_API_DEFAULT_TIMEOUT;
	session.retries=SNMP_API_DEFAULT_RETRIES;
	m_snmplock.Lock();
	ss=snmp_sess_open(&session);
	m_snmplock.UnLock();
	if(ss==NULL){
		WRONG("SNMP Create Error SysErr:%d SnmpErr:%d",session.s_errno,session.s_snmp_errno);
		return ss;
	}
	return ss;
}
void*CloseSnmp(void*session){
	if(session!=NULL){
		snmp_sess_close(session);
	}
	return NULL;
}
void ChangeSnmpSpecific(void*session,const char*Specific){
	netsnmp_session*sptr=snmp_sess_session(session);
	if(sptr){
		if(sptr->community)
			free(sptr->community);
		sptr->community = (u_char*)strdup(Specific);
		sptr->community_len = strlen(Specific);
	}
}
void ChangeSnmpTimeout(void*session,int timeoutms,int retries){
	if(session==NULL)return;
    netsnmp_session*sptr=snmp_sess_session(session);
    if(sptr){
        if(timeoutms>0)
           sptr->timeout=timeoutms*1000;
        if(timeoutms==-1)
           sptr->timeout=SNMP_API_DEFAULT_TIMEOUT;
        if(retries>0)
           sptr->retries=retries;
        if(retries==-1)
           sptr->retries=SNMP_API_DEFAULT_RETRIES;
    }
}

void ShowErrInfo(void* ss,netsnmp_pdu *pdu,int status){
	char OIDName[1024]={0};
	netsnmp_variable_list*vars;
	netsnmp_session*sptr=snmp_sess_session(ss);
	if(sptr==NULL)
		return;
	if(pdu!=NULL&&pdu->variables!=NULL){
		vars=pdu->variables;
		snprint_objid(OIDName,sizeof(OIDName),vars->name,vars->name_length);
	}
	if(status==STAT_TIMEOUT){
		if(strncmp(OIDName,"1.3.6.1.2.1.1.1.0",17)==0||strncmp(OIDName,".1.3.6.1.2.1.1.1.0",18)==0){
			WRONG("[IP:%s]STAT_TIMEOUT Maybe Not Open Snmp",sptr->peername);
		}else{
			WRONG("[IP:%s]STAT_TIMEOUT OID:%s",sptr->peername,OIDName);
		}
	}else
	if(status==STAT_ERROR){
		WRONG("[IP:%s]STAT_ERROR SysErr:%d SnmpErr:%d OID:%s",
				sptr->peername,sptr->s_errno,sptr->s_snmp_errno,
				OIDName);
	}
}


int CheckVars(const char*IP,netsnmp_variable_list *vars){
	if((vars->type == SNMP_ENDOFMIBVIEW)||
      (vars->type == SNMP_NOSUCHOBJECT)||
      (vars->type == SNMP_NOSUCHINSTANCE)||
      (vars->val_len==0)){
		char OIDName[1024]={0};
		snprint_objid(OIDName,sizeof(OIDName),vars->name,vars->name_length);
//跳过一些OID错误输出
#if 1
//进出包，mtu.inIndex
		if(strncmp(OIDName,".1.3.6.1.2.1.2.2.1.18.",22)==0||
			strncmp(OIDName,".1.3.6.1.2.1.2.2.1.12.",22)==0||
			strncmp(OIDName,".1.3.6.1.2.1.2.2.1.4.",21)==0||
			strncmp(OIDName,".1.3.6.1.2.1.2.2.1.6.",21)==0||
			strncmp(OIDName,".1.3.6.1.2.1.4.20.1.2.",22)==0||
			strncmp(OIDName,".1.3.6.1.2.1.47.1.1.1.1.2.",26)==0||
			strncmp(OIDName,".1.3.6.1.2.1.47.1.1.1.1.7.",26)==0||
			strcmp(OIDName,".1.3.6.1.4.1.4881.1.1.10.2.1.1.2.0")==0){
			return -1;
		}
#endif
		if(vars->type == SNMP_NOSUCHOBJECT){
			WRONG("IP[%s] OID(%s)No Such Object available on this agent at this OID",IP,OIDName);
		}else if(vars->type == SNMP_NOSUCHINSTANCE){
			WRONG("IP[%s] OID(%s)No Such Instance currently exists at this OID",IP,OIDName);
		}else if(vars->type == SNMP_ENDOFMIBVIEW){
			WRONG("IP[%s] OID(%s)No more variables left in this MIB View (It is past the end of the MIB tree)",IP,OIDName);
		}else if(vars->val_len==0){
			WRONG("IP[%s] OID(%s)With NULL Val",IP,OIDName);
		}
		return -1;
	}
	return 0;
}

#ifndef NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES
#define NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES 40 /* don't read host.conf files */
#endif
void ShowSnmpVersion(){
	printf("\033[01;33mNet-Snmp Version:%s\033[0m\n",netsnmp_get_version());
}
void InitNetSnmp(){
//必须优先初始化，否则多线程会有SNMP Create Error错误
    init_snmp("snmpapp");
    netsnmp_ds_set_int(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_OID_OUTPUT_FORMAT,NETSNMP_OID_OUTPUT_NUMERIC);
#if 0
	netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_DONT_BREAKDOWN_OIDS,1);
	if(netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES,1)==SNMPERR_SUCCESS)
		WARN("Set NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES SUCCESS");
	else
		WARN("Set NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES FAILED");
	INFO("NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES:%d",netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,NETSNMP_DS_LIB_DONT_LOAD_HOST_FILES));
#endif
}

void UnInitNetSnmp(){
#if 0
	snmp_shutdown("snmpapp");
#endif
}

const char*GetSnmpPeerName(void*session){
    netsnmp_session*sptr=snmp_sess_session(session);
    if(sptr==NULL)return NULL;
    return sptr->peername;
}
#if 0
typedef struct netsnmp_udp_addr_pair_s {
  struct sockaddr_in remote_addr;
  struct in_addr local_addr;
}netsnmp_udp_addr_pair;
void ChangeSnmpPeerName(void*session,const char*IP){
    netsnmp_session*sptr=snmp_sess_session(session);
    if((sptr!=NULL)&&(sptr->peername!=NULL)){
       INFO("local:%s peername:%s ",sptr->localname,sptr->peername);
       free(sptr->peername);
       sptr->peername=strdup(IP);
     }
#if 1
    netsnmp_transport*sptr2=snmp_sess_transport(session);
    if((sptr2!=NULL)&&(sptr2->remote!=NULL)){
       netsnmp_udp_addr_pair*peer=(netsnmp_udp_addr_pair*)&(sptr2->data);
       INFO("%s local:%ld remote:%ld date:%ld %ld %ld",
       inet_ntoa(peer->remote_addr.sin_addr),sptr2->local_length,sptr2->remote_length,sptr2->data_length,
       sizeof(struct sockaddr),sizeof(netsnmp_udp_addr_pair));
       //free(sptr2->remote);
       //sptr2->remote=strdup(IP);
     }
#endif
}
#endif
